/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.dos;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.type.FieldType;
import cn.easyplatform.type.ScopeType;

import java.io.Serializable;
import java.util.Date;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class FieldDo implements Serializable, Cloneable {

    /**
     *
     */
    private static final long serialVersionUID = -1036787986030364202L;

    /**
     * 应用范围
     */
    private ScopeType scope = ScopeType.FIELD;

    /**
     * 栏位或变量名称
     */
    private String name;

    /**
     * 参考java.sql.Types
     */
    private FieldType type;

    /**
     * 长度
     */
    private int length;

    /**
     * 小数位
     */
    private int decimal;

    /**
     * 栏位或变量的值
     */
    private Object value;

    /**
     * 关联的小数位
     */
    private String acc;

    /**
     * 变量共享方式
     */
    private int shareModel;

    /**
     * 描述
     */
    private String description;

    /**
     * 原始名称
     */
    private String rawName;

    private int optionType;

    private String optionValue;

    public FieldDo() {
    }

    public FieldDo(FieldType type) {
        this.type = type;
        switch (type) {
            case INT:
                value = 0;
                break;
            case LONG:
                value = 0L;
                break;
            case NUMERIC:
                value = 0d;
                break;
            case VARCHAR:
            case CLOB:
                value = "";
                break;
            case CHAR:
                value = ' ';
                break;
            case BOOLEAN:
                value = false;
                break;
            default:
                value = null;
        }
    }

    public FieldDo(FieldType type, Object value) {
        this.type = type;
        setValue(value);
    }

    public FieldDo(String name, FieldType type, Object value) {
        this.type = type;
        setName(name);
        setValue(value);
    }

    public ScopeType getScope() {
        return scope;
    }

    public void setScope(ScopeType scope) {
        this.scope = scope;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.rawName = name;
        this.name = name == null ? "" : name.toUpperCase();
    }

    public String getRawName() {
        return this.rawName;
    }

    public FieldType getType() {
        return type;
    }

    public void setType(FieldType type) {
        this.type = type;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public int getDecimal() {
        return decimal;
    }

    public void setDecimal(int decimal) {
        this.decimal = decimal;
    }

    public Object getValue() {
        return value;
    }

    public int getOptionType() {
        return optionType;
    }

    public void setOptionType(int optionType) {
        this.optionType = optionType;
    }

    public String getOptionValue() {
        return optionValue;
    }

    public void setOptionValue(String optionValue) {
        this.optionValue = optionValue;
    }

    public void setValue(Object value) {
        if (value != null) {
            switch (type) {
                case INT:
                    if (value instanceof Number)
                        value = ((Number) value).intValue();
                    else if (value instanceof Boolean)
                        value = (Boolean) value ? 1 : 0;
                    else
                        throw new EasyPlatformWithLabelKeyException(
                                "entity.field.value.error", rawName,
                                type.toString(), value.getClass().getSimpleName());
                    break;
                case LONG:
                case NUMERIC:
                    if (value instanceof Number) {
                        if (type == FieldType.NUMERIC)
                            value = ((Number) value).doubleValue();
                        else
                            value = ((Number) value).longValue();
                    } else
                        throw new EasyPlatformWithLabelKeyException(
                                "entity.field.value.error", rawName,
                                type.toString(), value.getClass().getSimpleName());
                    break;
                case VARCHAR:
                case CLOB:
                    if (value instanceof Boolean) {
                        if (length == 1)
                            value = ((Boolean) value) ? "1" : "0";
                        else
                            value = ((Boolean) value) ? "true" : "false";
                    } else if (!(value instanceof CharSequence)
                            && !(value instanceof Character))
                        throw new EasyPlatformWithLabelKeyException(
                                "entity.field.value.error", rawName,
                                type.toString(), value.getClass().getSimpleName());
                    value = value.toString();
                    break;
                case CHAR:
                    if (!(value instanceof CharSequence)
                            && !(value instanceof Character))
                        throw new EasyPlatformWithLabelKeyException(
                                "entity.field.value.error", rawName,
                                type.toString(), value.getClass().getSimpleName());
                    value = value.toString().length() > 0 ? value.toString()
                            .charAt(0) : ' ';
                    break;
                case DATE:
                case DATETIME:
                case TIME:
                    if (value instanceof Long) {
                        value = new Date((Long) value);
                    } else if (!(value instanceof Date))
                        throw new EasyPlatformWithLabelKeyException(
                                "entity.field.value.error", rawName,
                                type.toString(), value.getClass().getSimpleName());
                    break;
                case BOOLEAN:
                    if (value instanceof Number) {
                        value = ((Number) value).intValue() > 0 ? true : false;
                    } else if (!(value instanceof Boolean)) {
                        String str = value.toString();
                        if (str.length() == 1) {
                            if ("1".equals(str) || "T".equals(str))
                                value = true;
                            else
                                value = false;
                        } else
                            value = value.toString().equalsIgnoreCase("true");
                    }
                    break;
                case BLOB:
                case OBJECT:
                    if (!(value instanceof Serializable))
                        throw new EasyPlatformWithLabelKeyException(
                                "entity.field.value.error", rawName,
                                type.toString(), value.getClass().getSimpleName());
                default:
            }
        }
        this.value = value;
    }

    public void setRawValue(Object value) {
        this.value = value;
    }

    public String getAcc() {
        return acc;
    }

    public void setAcc(String acc) {
        this.acc = acc;
    }

    @Override
    public String toString() {
        return rawName + "=" + value;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public int getShareModel() {
        return shareModel;
    }

    public void setShareModel(int shareModel) {
        this.shareModel = shareModel;
    }

    public boolean isEmpty() {
        if (value == null)
            return true;
        if ((type == FieldType.INT || type == FieldType.LONG)
                && ((Number) value).intValue() == 0)
            return true;
        if (type == FieldType.NUMERIC && ((Number) value).doubleValue() == 0d)
            return true;
        if (type == FieldType.CHAR || type == FieldType.VARCHAR
                || type == FieldType.CLOB)
            return Strings.isBlank(value.toString());
        return false;
    }

    @Override
    public FieldDo clone() {
        try {
            return (FieldDo) super.clone();
        } catch (Exception ex) {
        }
        return null;
    }

    public static FieldDo NULL() {
        return new FieldDo(FieldType.OBJECT);
    }
}
